#import "BWGridGeometry.h"

#import "BWFabric.h"


@implementation BWGridGeometry

- (void) trackFabricChange
{
    int count;
    count = [fabric width] * [fabric count] / [fabric overX];
    [self setCountAcross: count];

    count = [fabric height] * [fabric count] / [fabric overX];
    [self setCountDown: count];

} // trackFabricChange


- (void) setFabric: (BWFabric *) f
{
    [fabric removeObserver: self
            forKeyPath: @"fabricChange"];

    [f retain];
    [fabric release];
    fabric = f;

    [f addObserver: self
       forKeyPath: @"fabricChange"
       options: NSKeyValueObservingOptionNew
       context: NULL];
    
    [self trackFabricChange];

} // setFabric


- (BWFabric *) fabric
{
    return (fabric);
} // fabric


- (float) width
{
    float width = cellWidth * countAcross;
    
    return (width);

} // width


- (float) height
{
    float height = cellHeight * countDown;

    return (height);

} // height


- (NSRect) rectForRow: (int) row
               column: (int) column
{
    NSRect rect;
    rect.origin.x = cellWidth * column + 1;
    rect.origin.y = cellHeight * row + 1;
    
    rect.size.width = cellWidth - 1;
    rect.size.height = cellHeight - 1;

    return (rect);

} // rectForRow


- (NSPoint) pointForIntersectionAtRow: (int) row
                               column: (int) column
{
    NSPoint point;

    point.x = column * cellWidth;
    point.y = row * cellHeight;

    return (point);

} // pointForIntersectionAtRow


- (void) getRow: (int *) row
      andColumn: (int *) column
        atPoint: (NSPoint) point
{
    if (row != NULL) {
        *row = point.y / cellHeight;
    }

    if (column != NULL) {
        *column = point.x / cellWidth;
    }

} // getRow


- (void) getIntersectionRow: (int *) row
                  andColumn: (int *) column
                  nearPoint: (NSPoint) point
{
    point.x += cellWidth / 2.0;
    point.y += cellHeight / 2.0;

    [self getRow: row
          andColumn: column
          atPoint: point];

} // getIntersectionRow


// --------------------------------------------------
// "dumb" accessors


- (void) setCountAcross: (int) across
{
    countAcross = across;
} // setCountAcross


- (void) setCountDown: (int) down
{
    countDown = down;
} // setCountDown


- (int) countAcross
{
    return (countAcross);
} // countAcross


- (int) countDown
{
    return (countDown);
} // countDown


- (void) setCellWidth: (float) width
{
    cellWidth = width;
} // setCellWidth


- (float) cellWidth
{
    return (cellWidth);
} // cellWidth



- (void) setCellHeight: (float) height
{
    cellHeight = height;
} // setCellHeight


- (float) cellHeight
{
    return (cellHeight);
} // cellHeight


- (void) getIntersectionRow: (int *) row
                     column: (int *) column
                   quadrant: (BWGrid_Quadrant *) quad
                  nearPoint: (NSPoint) point
{
    BWGrid_Quadrant quadrant = kQuadrant_None;

    [self getRow: row
          andColumn: column
          atPoint: point];

    // that gives us the cell it's in
    NSRect cellRect;
    cellRect = [self rectForRow: *row  column: *column];

    // now see what part the point is near.  Hit-test rectangles that
    // are half the size of the cell, in a grid 3x3 over the original cell
    float w2, h2, w4, h4;  // 1/2 and 1/4
    w2 = cellWidth / 2.0;
    h2 = cellHeight / 2.0;
    w4 = cellWidth / 4.0;
    h4 = cellHeight / 4.0;

    NSRect testRect;
    testRect.size = NSMakeSize (w2, h2);

    // ------------------------------
    // top row of thirds

    testRect.origin.x = cellRect.origin.x - w4;
    testRect.origin.y = cellRect.origin.y - h4;

    if (NSPointInRect(point, testRect)) {
        quadrant = kQuadrant_NW;
        goto done;
    }

    testRect.origin.x += w2;

    if (NSPointInRect(point, testRect)) {
        quadrant = kQuadrant_Top;
        goto done;
    }

    testRect.origin.x += w2;

    if (NSPointInRect(point, testRect)) {
        quadrant = kQuadrant_NE;
        goto done;
    }
    
    // ------------------------------
    // middle row of thirds

    testRect.origin.x = cellRect.origin.x - w4;
    testRect.origin.y = cellRect.origin.y + h4;

    if (NSPointInRect(point, testRect)) {
        quadrant = kQuadrant_Left;
        goto done;
    }

    testRect.origin.x += w2;

    if (NSPointInRect(point, testRect)) {
        quadrant = kQuadrant_Center;
        goto done;
    }

    testRect.origin.x += w2;

    if (NSPointInRect(point, testRect)) {
        quadrant = kQuadrant_Right;
        goto done;
    }

    // ------------------------------
    // bottom row of thirds

    testRect.origin.x = cellRect.origin.x - w4;
    testRect.origin.y = cellRect.origin.y + h4 + h2;

    if (NSPointInRect(point, testRect)) {
        quadrant = kQuadrant_SW;
        goto done;
    }

    testRect.origin.x += w2;

    if (NSPointInRect(point, testRect)) {
        quadrant = kQuadrant_Bottom;
        goto done;
    }

    testRect.origin.x += w2;

    if (NSPointInRect(point, testRect)) {
        quadrant = kQuadrant_SE;
        goto done;
    }

done:
    *quad = quadrant;

} // getIntersectionRow+quadrant



- (NSPoint) pointForIntersectionAtRow: (int) row
                               column: (int) column
                             quadrant: (BWGrid_Quadrant) quadrant
{
    NSRect cellRect;
    cellRect = [self rectForRow: row  column: column];

    NSPoint point = cellRect.origin;

    switch (quadrant) {
    case kQuadrant_Top:
        point.x += cellWidth / 2.0;
        break;
    case kQuadrant_Bottom:
        point.x += cellWidth / 2.0;
        point.y += cellHeight;
        break;
    case kQuadrant_Left:
        point.y += cellHeight / 2.0;
        break;
    case kQuadrant_Right:
        point.x += cellWidth;
        point.y += cellHeight / 2.0;
        break;
    case kQuadrant_NW:
        // no-op
        break;
    case kQuadrant_NE:
        point.x += cellWidth;
        break;
    case kQuadrant_SW:
        point.y += cellHeight;
        break;
    case kQuadrant_SE:
        point.x += cellWidth;
        point.y += cellHeight;
        break;
    case kQuadrant_Center:
        point.x += cellWidth / 2;
        point.y += cellHeight / 2;
        break;
    }

    return (point);

} // pointForIntersectionAtRow+quadrant


- (void) observeValueForKeyPath: (NSString *) keyPath
                       ofObject: (id) object
                         change: (NSDictionary *) change
                        context: (void *) context
{
    if ([keyPath isEqualToString: @"fabricChange"]) {
        [self trackFabricChange];
    }

} // observeValueForKeyPath


@end // BWGridGeometry
